package cn.yunhe.java.security;

import cn.yunhe.java.security.filter.VerificationCodeFilter;
import cn.yunhe.java.security.provider.MyWebAuthenticationDetailsSource;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationDetailsSource;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.security.web.authentication.WebAuthenticationDetails;

import javax.servlet.http.HttpServletRequest;

@Configuration //声明该类是一个配置类
@EnableWebSecurity(debug = false)
//@EnableGlobalMethodSecurity(prePostEnabled=true) 该注解不生效
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

    //自定义加密方式
    //@Autowired
    //private SHA256Encoder sha256Encoder;
    //注入自定义认证过程
    @Autowired
    private AuthenticationDetailsSource<HttpServletRequest, WebAuthenticationDetails> myWebAuthenticationDetailsSource;

    @Autowired
    private UserDetailsService userDetailsService;//用户详情查询接口

    @Autowired
    private AuthenticationProvider authenticationProvider;

    /**
     * 方法的返回值对象进spring 容器
     * @return
     */
    @Bean
    public BCryptPasswordEncoder passwordEncoder(){
        return  new BCryptPasswordEncoder();
    }
    //认证
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        //配置内存认证账号
//        auth.inMemoryAuthentication()
//                .passwordEncoder(new BCryptPasswordEncoder())
//                .withUser("tom")
//                .password(new BCryptPasswordEncoder().encode("123123")) //设置账号密码
//                .roles("ADMIN") //设置角色
//                .and()
//                .withUser("jerry")
//                .password(new BCryptPasswordEncoder().encode("456456"))//设置另一个账号密码
//                .authorities("SAVE","EDIT"); //设置权限

        //自定义加密方式
        //auth.userDetailsService(userDetailsService).passwordEncoder(sha256Encoder);
        //使用spring security提供的BCrypt加密方式

        //auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder());
        //自定义认证过程
        auth.authenticationProvider(authenticationProvider);
    }

    //安全控制
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        //super.configure(http); //不能再走父类的业务逻辑

        http.csrf().disable(); //关闭防跨站请求处理

        http.authorizeRequests() //对请求进行授权
                .antMatchers("/statics/**","/login/**") //使用 ANT 风格设置要授权的 URL 地 址
                .permitAll() //允许上面使用 ANT 风格设置的全部请求
                 //授权资源访问
             // .antMatchers("/user/**").hasRole("管理员1")
                //.antMatchers("/user/**").fullyAuthenticated() //如果用户是完整认证的话(不是通过Remember-me功能认证的)，允许访问

                .anyRequest() //其他未设置的全部请求
                .authenticated() //需要认证(登录之后才能访问)
             .and()
                //未授权的页面错误信息，不显示403错误
                .exceptionHandling().accessDeniedPage("/error/unAuthorized")
             .and()
                 .headers()  //防止iframe攻击，layui使用了iframe技术，所以需要禁用
                 .frameOptions().sameOrigin()
                 .httpStrictTransportSecurity().disable()
             .and()
                .formLogin() //设置未授权请求跳转到登录页面：没有权限访问的资源进入登录页
                .loginPage("/login/index") //指定登录页
                .authenticationDetailsSource(myWebAuthenticationDetailsSource)
                .loginProcessingUrl("/hzn") // 指定提交登录表单的地址,该地址是个假地址
                .permitAll() //为登录页设置所有人都可以访问
                .usernameParameter("userName") // 定制登录账号的请求参数名
                .passwordParameter("password") // 定制登录密码的请求参数名
                .defaultSuccessUrl("/login/main") //设置登录成功后默认前往的 URL 地址
            .and()
                .logout()
                .logoutUrl("/login/logout")
                //前后端分离开发使用
//                .logoutSuccessHandler(new LogoutSuccessHandler() {
//                    @Override
//                    public void onLogoutSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {
//                        response.setContentType("application/json;charset=8tf-8");
//                        //返回json数据
//                    }
//                })
                .logoutSuccessUrl("/login/index");

        //记住我功能
        //如果是自定义的认证过程，需要在rememberMe()后面指定UserDetailsService
        http.rememberMe().userDetailsService(userDetailsService);

            //添加自定义的过滤器
            //添加到账号密码过滤器之前
            //添加了自定义的认证过程，可以去掉这个过滤器了
        //http.addFilterBefore(new VerificationCodeFilter(), UsernamePasswordAuthenticationFilter.class);

        //设置用户登录到系统的会话个数
        http.sessionManagement().maximumSessions(2);
    }
}
